package com.zhouheng.springbootmultithreading.common.utils;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zhouheng.springbootmultithreading.common.exception.BaseException;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;


public final class JsonUtil {

    /**
     * OBJECT_MAPPER 描述此常量
     */
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    static {
        OBJECT_MAPPER.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        OBJECT_MAPPER.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
    }

    /**
     * 描述此方法实现的功能
     *
     * @param <T>       描述此泛型参数
     * @param jsonStr   描述此参数
     * @param valueType 描述此参数
     * @return 返回 t 描述此返回参数
     * @author LeoRmAo
     * @date 20181026 10:57:21
     * @since v1.0
     */
    public static <T> T parseJson(String jsonStr, Class<T> valueType) {
        try {
            return OBJECT_MAPPER.readValue(jsonStr, valueType);
        } catch (Exception e) {
            throw new BaseException(e.getMessage());
        }
    }

    /**
     * 描述此方法实现的功能
     *
     * @param <T>           描述此泛型参数
     * @param jsonStr       描述此参数
     * @param typeReference 描述此参数
     * @return 返回 t 描述此返回参数
     * @author LeoRmAo
     * @date 20181026 10:57:21
     * @since v1.0
     */
    public static <T> T parseJson(String jsonStr, TypeReference typeReference) {
        try {
            return OBJECT_MAPPER.readValue(jsonStr, typeReference);
        } catch (Exception e) {
            throw new BaseException(e.getMessage());
        }
    }

    /**
     * 描述此方法实现的功能
     *
     * @param <T>       描述此泛型参数
     * @param map       描述此参数
     * @param valueType 描述此参数
     * @return 返回 t 描述此返回参数
     * @author LeoRmAo
     * @date 20181026 10:57:21
     * @since v1.0
     */
    public static <T> T parseObject(Map map, Class<T> valueType) {
        try {
            return OBJECT_MAPPER.convertValue(map, valueType);
        } catch (Exception e) {
            throw new BaseException(e.getMessage());
        }
    }

    /**
     * 描述此方法实现的功能
     *
     * @param <T>            描述此泛型参数
     * @param jsonStr        描述此参数
     * @param parentClass    描述此参数
     * @param elementClasses 描述此参数
     * @return 返回 t 描述此返回参数
     * @author LeoRmAo
     * @date 20181026 10:57:21
     * @since v1.0
     */
    public static <T> T parseJson(String jsonStr, Class<?> parentClass, Class<?>... elementClasses) {
        JavaType javaType = getCollectionType(parentClass, elementClasses);
        try {
            return OBJECT_MAPPER.readValue(jsonStr, javaType);
        } catch (IOException e) {
            throw new BaseException(e.getMessage());
        }
    }

    /**
     * 描述此方法实现的功能
     *
     * @param object 描述此参数
     * @return 返回 string 描述此返回参数
     * @author LeoRmAo
     * @date 20181026 10:57:21
     * @since v1.0
     */
    public static String toJson(Object object) {
        try {
            return OBJECT_MAPPER.writeValueAsString(object);
        } catch (Exception e) {
            throw new BaseException(e.getMessage());
        }
    }

    /**
     * 描述此方法实现的功能
     *
     * @param <T>     描述此泛型参数
     * @param jsonStr 描述此参数
     * @param c       描述此参数
     * @return 返回 list 描述此返回参数
     * @author LeoRmAo
     * @date 20181026 10:57:21
     * @since v1.0
     */
    public static <T> List<T> parseList(String jsonStr, Class<T> c) {
        JavaType javaType = getCollectionType(ArrayList.class, c);
        try {
            return OBJECT_MAPPER.readValue(jsonStr, javaType);
        } catch (IOException e) {
            throw new BaseException(e.getMessage());
        }
    }

    /**
     * 获取 collection type.
     *
     * @param collectionClass 描述此参数
     * @param elementClasses  描述此参数
     * @return 返回 collection type
     * @author LeoRmAo
     * @date 20181026 10:57:21
     * @since v1.0
     */
    private static JavaType getCollectionType(Class<?> collectionClass, Class<?>... elementClasses) {
        return OBJECT_MAPPER.getTypeFactory().constructParametricType(collectionClass, elementClasses);
    }

}
